package com.hanter.android.radlib.saf;

import android.Manifest;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;

import com.hanter.android.radlib.util.FileUtils;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


/**
 * App 代表 App的私有目录（内部存储+外部存储），
 * 相对于共有目录则是： Environment.DIRECTORY_ 对应的目录
 * 内部存储用 File，外部存储用 Uri
 */
public class FileManager implements SafManager {

    public static final String TAG = FileManager.class.getSimpleName();

    private final Context context;
    // 应用文件目录
    private final String appDir;
    private final String path;
    private final String tempPath;
    private final String authority;
    public final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);

    public FileManager(@NonNull Context context) {
        this(context, null);
    }

    public FileManager(@NonNull Context context, @Nullable String authority) {
        this.context = context.getApplicationContext();
        File picturesDir = this.context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        this.appDir = this.context.getPackageName();
        if (FileUtils.existsExternalStorage() && picturesDir != null) {
            this.path = picturesDir.getAbsolutePath() + File.separator + appDir;
        } else {
            this.path = this.context.getFilesDir() + File.separator + appDir;
        }
        this.tempPath = this.path + File.separator + "temp";
        this.authority = authority != null ? authority : (this.context.getPackageName() + ".fileprovider");
    }

    @Override
    public Uri getMediaContentUri(String type) {
        return getMediaContentUri(type, true);
    }

    @Override
    public Uri getMediaContentUri(String type, boolean external) {
        // Images(Pictures DCIM)
        if (Environment.DIRECTORY_PICTURES.equals(type) || Environment.DIRECTORY_DCIM.equals(type)) {
            return external ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    : MediaStore.Images.Media.INTERNAL_CONTENT_URI;
        }

        // Video(Movies)
        if (Environment.DIRECTORY_MOVIES.equals(type)) {
            return external ? MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                    : MediaStore.Video.Media.INTERNAL_CONTENT_URI;
        }

        // Audio
        if (Environment.DIRECTORY_MUSIC.equals(type) || Environment.DIRECTORY_PODCASTS.equals(type)
                || Environment.DIRECTORY_RINGTONES.equals(type)
                || Environment.DIRECTORY_ALARMS.equals(type)
                || Environment.DIRECTORY_NOTIFICATIONS.equals(type)) {
            return external ? MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                    : MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            if (Environment.DIRECTORY_SCREENSHOTS.equals(type)) {
                return external ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                        : MediaStore.Images.Media.INTERNAL_CONTENT_URI;
            }

            if (Environment.DIRECTORY_AUDIOBOOKS.equals(type)) {
                // TODO Documents
                return MediaStore.Files.getContentUri(external ? "external" : "internal");
            }
        }

        // Downloads
        if (Environment.DIRECTORY_DOWNLOADS.equals(type) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return external ? MediaStore.Downloads.EXTERNAL_CONTENT_URI
                    : MediaStore.Downloads.INTERNAL_CONTENT_URI;
        }

        // Files 允许Documents和Downloads目录
        return MediaStore.Files.getContentUri(external ? "external" : "internal");
    }

    @Override
    public Uri createMediaUri(String type, String fileName) throws IOException {
        return createMediaUri(type, fileName, (ContentValues) null);
    }

    @Override
    public Uri createMediaUri(String type, String fileName, String mimeType) throws IOException {
        ContentValues other = new ContentValues();
        other.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
        return createMediaUri(type, fileName, other);
    }

    private Uri createMediaUri(String type, String fileName, @Nullable ContentValues other) throws IOException {
        if (!FileUtils.existsExternalStorage())
            throw new IOException("创建失败，外部存储可不用！");

        Uri uri;
        // 使用公共存储目录，还是使用 App 存储目录？
        if (hasExternalPermission()) {
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
            if (other != null)
                contentValues.putAll(other);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                // 参考：https://developer.android.com/reference/android/provider/MediaStore.MediaColumns#RELATIVE_PATH
                // android Q中不再使用DATA字段，而用RELATIVE_PATH代替，RELATIVE_PATH是相对路径不是绝对路径
                // 如果文件 /storage/0000-0000/DCIM/Vacation/IMG1024.JPG 则它的路径为 DCIM/Vacation/
                // 可以传空，但会根据媒体类型自动选择目录；如果你填了 audio/mpeg 到 PICTURES 会报错，类型相关目录
                // 根据 type 选择 路径
                contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, getRelativePath(type));
            } else {
                // 低于 Q 手动创建，然后授权 读写
                File mediaFile = createMediaFile(type, fileName);
                contentValues.put(MediaStore.Images.Media.DATA, mediaFile.getPath());
            }
            uri = context.getContentResolver().insert(
                    getMediaContentUri(type, FileUtils.existsExternalStorage()),
                    contentValues
            );
        } else {
            // 对于没有存储权限，只能在 context.getExternalFilesDir 目录创建（不需要存储权限）
            File mediaFile = createMediaFile(type, fileName);
            // 创建文件
            File parent = mediaFile.getParentFile();
            if (parent != null && !parent.exists() && parent.mkdirs()) {
                if (!mediaFile.exists())
                    //noinspection ResultOfMethodCallIgnored
                    mediaFile.createNewFile();
            }
            uri = FileProvider.getUriForFile(this.context, this.authority, mediaFile);
        }

        // 目标存储的URI
        if (uri != null)
            Log.d(TAG, "mediaUri: " + uri.toString());
        else
            Log.d(TAG, "mediaUri failed. type: " + type);
        return uri;
    }

    @Override
    public Uri createImageUri(String fileName) throws IOException {
        return createImageUri(fileName, null);
    }

    @Override
    public Uri createImageUri(String fileName, String mimeType) throws IOException {
        ContentValues other = new ContentValues();
        other.put(MediaStore.MediaColumns.MIME_TYPE, mimeType != null ? mimeType : "image/jpeg");
        return createMediaUri(Environment.DIRECTORY_PICTURES, fileName, other);
    }

    @Override
    public File getAppMediaDirectory(String type, boolean external) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (hasExternalPermission() && FileUtils.existsExternalStorage()) {
                return this.context.getExternalFilesDir(type);
            } else {
                return new File(this.context.getFilesDir(), type);
            }
        } else if (FileUtils.existsExternalStorage()) {
            return this.context.getExternalFilesDir(type);
        } else {
            return new File(this.context.getFilesDir(), type);
        }
    }

    @Override
    public File getAppFilesDirectory(boolean external) {
        if (external && FileUtils.existsExternalStorage()) {
            return this.context.getExternalFilesDir(null);
        } else {
            return this.context.getFilesDir();
        }
    }

    /**
     * 外部存储是否可写入（外部写入权限）
     */
    private boolean isExternalWritable() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return this.context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && FileUtils.existsExternalStorage();
        } else {
            return FileUtils.existsExternalStorage();
        }
    }

    private boolean hasExternalPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return this.context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
        } else {
            return true;
        }
    }

    private File getMediaDirectory(String type) {
        if (isExternalWritable()) {
            return getPublicMediaDirectory(type);
        } else {
            return new File(getAppFilesDirectory(FileUtils.existsExternalStorage()), type);
        }

        /*
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (this.context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                    && FileUtils.existsExternalStorage()) {
                return getPublicMediaDirectory(type);
            } else {
                return new File(getAppFilesDirectory(false), type);
            }
        } else if (FileUtils.existsExternalStorage()) {
            return getPublicMediaDirectory(type);
        } else {
            // 使用了内部存储，不再使用 getPublicMediaDirectory() 嵌套目录
            return new File(getAppFilesDirectory(false), type);
        }
        */
    }

    /**
     * 获取外部公共存储的目录
     */
    private File getPublicMediaDirectory(String type) {
        // 根据类型调整目录，达到 < Q 和 Q 目录统一性

        if ("Audiobooks".equals(type)) {
            return new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "Audiobooks");
        }

        if ("Screenshots".equals(type)) {
            return new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Screenshots");
        }

        return Environment.getExternalStoragePublicDirectory(type);
    }

    private String getRelativePath(String type) {
        // Audiobooks allowed directories are [Download, Documents]

        if ("Audiobooks".equals(type)) {
            return Environment.DIRECTORY_DOCUMENTS + File.separator + "Audiobooks";
        } else if ("Screenshots".equals(type)) {
            return Environment.DIRECTORY_PICTURES + File.separator + "Screenshots";
        }

        return type;
    }

    // TODO < Q 判断是否正确

    /**
     * 创建媒体文件，Api < Build.VERSION_CODES.Q
     * @param type
     * @param fileName
     * @return
     */
    public File createMediaFile(String type, String fileName) {
        File file = new File(getMediaDirectory(type), fileName);
        Log.d(TAG, "创建文件：" + file.getAbsolutePath());
        return file;
    }

    private String getDatePrefix() {
        return dateFormat.format(new Date());
    }

    public File createImageFile(String fileName) throws IOException {
        File file = new File(getMediaDirectory(Environment.DIRECTORY_PICTURES), fileName);
        Log.d(TAG, "创建文件：" + file.getAbsolutePath());
        return file;
    }

    public File createImageFile() throws IOException {
        return createImageFile(genImageFileName());
    }

    public String genImageFileName() {
        String datePrefix = getDatePrefix();
        long time = System.currentTimeMillis() % (1000 * 60 * 60);
        return "IMG_" + datePrefix + "_" + time + ".jpg";
    }

    /**
     * 创建临时图片文件
     */
    public File createTempImageFile() throws IOException {
        String datePrefix = getDatePrefix();
        String prefix = "IMG_TEMP_" + datePrefix + "_";
        String suffix = ".jpg";

        File file = createTempFile(prefix, suffix);
        Log.d(TAG, "创建临时文件：" + file.getAbsolutePath());
        return file;
    }

    /**
     * 创建临时文件，目录（external://mfcar/dealer/tmp）
     */
    public File createTempFile(String prefix, String suffix) throws IOException {
        File tmpDir = new File(this.tempPath);

        boolean dirExists = tmpDir.exists() || tmpDir.mkdirs();
        if (!dirExists) {
            throw new IOException("create temp dir is failed");
        }

        File file = File.createTempFile(prefix, suffix, tmpDir);
        if (!file.exists()) {
            File parent = file.getParentFile();
            if (parent == null || parent.exists() || parent.mkdirs()) {
                if (file.createNewFile()) {
                    Log.d(TAG, "create temp file.");
                } else {
                    Log.d(TAG, "temp file is existed.");
                }
            } else { // 忽略创建目录
                Log.d(TAG, "mk parent dirs of temp file is failed.");
            }
        }
        return file;
    }

    public static File createFile(File dir, String name) {
        File file = new File(dir, name);
        if (!file.exists()) {
            File parent = file.getParentFile();
            if (parent == null || parent.exists() || parent.mkdirs()) {
                try {
                    // 忽略创建文件结果
                    //noinspection ResultOfMethodCallIgnored
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }

    public File createFile(String name) {
        File file = new File(this.path, name);
        if (!file.exists()) {
            File parent = file.getParentFile();
            if (parent == null || parent.exists() || parent.mkdirs()) {
                try {
                    // 忽略创建文件结果
                    //noinspection ResultOfMethodCallIgnored
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }

    public void deleteTempFiles() { // 可以删除临时目录
        File file = new File(tempPath);
        SafFileUtils.deleteDirectory(file);
    }

}
